using System.Net;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using mvcincode.Auth.Requirement;

namespace mvcincode.Auth.Handler;

public class MyAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
    private readonly AuthorizationMiddlewareResultHandler DefaultHandler
        = new AuthorizationMiddlewareResultHandler();

    public async Task HandleAsync(
        RequestDelegate next,
        HttpContext httpContext,
        AuthorizationPolicy authorizationPolicy,
        PolicyAuthorizationResult policyAuthorizationResult)
    {

        var logger = httpContext.RequestServices.GetRequiredService<ILogger<MyAuthorizationMiddlewareResultHandler>>();

        // 指示未经身份验证的用户请求访问需要身份验证的终结点
        if (policyAuthorizationResult.Challenged)
        {
            logger.LogInformation("policyAuthorizationResult: Challenged");

            if (authorizationPolicy.AuthenticationSchemes.Count > 0)
            {
                foreach (var scheme in authorizationPolicy.AuthenticationSchemes)
                {
                    await httpContext.ChallengeAsync(scheme);
                }
            }
            else
            {
                await httpContext.ChallengeAsync();
            }
 
            return;
        }
        else if (policyAuthorizationResult.Forbidden)  // 验证失败
        {
            logger.LogInformation("policyAuthorizationResult: Forbidden");

            // if the authorization was forbidden and the resource had specific requirements,
            // provide a custom response.
            if (Show404ForForbiddenResult(policyAuthorizationResult))
            {
                // Return a 404 to make it appear as if the resource does not exist.
                httpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                logger.LogInformation("show 404 status code in response");
                return;
            }

            // Fallback to the default implementation.
            await DefaultHandler.HandleAsync(next
                , httpContext
                , authorizationPolicy
                , policyAuthorizationResult);
        }

        // 最后成功要放行
        logger.LogInformation("policyAuthorizationResult: Succeeded");
        await next(httpContext);
    }

    bool Show404ForForbiddenResult(PolicyAuthorizationResult policyAuthorizationResult)
    {
        return policyAuthorizationResult.Forbidden &&
            policyAuthorizationResult
                .AuthorizationFailure
                .FailedRequirements
                .OfType<Show404Requirement>()
                .Any();
    }
}


